/*
 * Copyright (c) zhg2yqq.com Corp.
 * All Rights Reserved.
 */
package com.zhg2yqq.wheels.mvc.base;

import java.io.Serializable;
import java.util.List;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zhg2yqq.wheels.mvc.wrapper.EncryptQueryWrapper;

import cn.hutool.core.text.CharSequenceUtil;

/**
 * @author zhg2yqq, 2022年12月5日
 * @version zhg2yqq v1.0
 */
public class BaseCondition<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    private String filters;
    private String sorts;

    public QueryWrapper<T> getQueryWrapper() {
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        buildQueryWrapper(wrapper);
        return builOrderToWrapper(wrapper);
    }

    public QueryWrapper<T> getQueryWrapper(String key, Class<T> genericType) {
        EncryptQueryWrapper<T> wrapper = new EncryptQueryWrapper<>(key, genericType);
        buildQueryWrapper(wrapper);
        return builOrderToWrapper(wrapper);
    }

    private QueryWrapper<T> buildQueryWrapper(QueryWrapper<T> wrapper) {
        if (CharSequenceUtil.isEmpty(filters)) {
            return wrapper;
        }
        List<FiledFilter> filterObjs = JSON.parseArray(filters, FiledFilter.class);
        for (FiledFilter filter : filterObjs) {
            String field = CharSequenceUtil.toUnderlineCase(filter.getF());
            if ("=".equals(filter.o) || CharSequenceUtil.isEmpty(filter.o)) {
                wrapper.eq(field, filter.getV());
            } else if (CharSequenceUtil.equalsAny(filter.o, "!=", "<>")) {
                wrapper.ne(field, filter.getV());
            } else if (">".equals(filter.o)) {
                wrapper.gt(field, filter.getV());
            } else if (">=".equals(filter.o)) {
                wrapper.ge(field, filter.getV());
            } else if ("<".equals(filter.o)) {
                wrapper.lt(field, filter.getV());
            } else if ("<=".equals(filter.o)) {
                wrapper.le(field, filter.getV());
            } else if (CharSequenceUtil.equalsIgnoreCase(filter.o, "in")) {
                JSONArray values;
                if (filter.getV() instanceof String) {
                    values = JSONArray.parseArray((String) filter.getV());
                } else {
                    values = (JSONArray) filter.getV();
                }
                wrapper.in(field, values.toArray());
            } else if (CharSequenceUtil.equalsAnyIgnoreCase(filter.o, "notin", "not in")) {
                JSONArray values;
                if (filter.getV() instanceof String) {
                    values = JSONArray.parseArray((String) filter.getV());
                } else {
                    values = (JSONArray) filter.getV();
                }
                wrapper.notIn(field, values.toArray());
            } else if (CharSequenceUtil.equalsIgnoreCase(filter.o, "startwith")) {
                wrapper.likeRight(field, filter.getV());
            } else if (CharSequenceUtil.equalsIgnoreCase(filter.o, "contains")) {
                wrapper.like(field, filter.getV());
            } else if (CharSequenceUtil.equalsAnyIgnoreCase(filter.o, "isnull", "is null")) {
                wrapper.isNull(field);
            } else if (CharSequenceUtil.equalsAnyIgnoreCase(filter.o, "isnotnull", "is not null")) {
                wrapper.isNotNull(field);
            } else if (CharSequenceUtil.equalsIgnoreCase(filter.o, "between")) {
                JSONArray values;
                if (filter.getV() instanceof String) {
                    values = JSONArray.parseArray((String) filter.getV());
                } else {
                    values = (JSONArray) filter.getV();
                }
                wrapper.between(field, values.get(0), values.get(1));
            } else if (CharSequenceUtil.equalsIgnoreCase(filter.o, "inset")) {
                // mysql FIND_IN_SET方法
                wrapper.apply("FIND_IN_SET({0}," + CharSequenceUtil.toUnderlineCase(filter.f) + ")", filter.getV());
            }
        }
        return wrapper;
    }

    protected QueryWrapper<T> builOrderToWrapper(QueryWrapper<T> wrapper) {
        if (CharSequenceUtil.isNotEmpty(sorts)) {
            List<FieldSort> sortObjs = JSON.parseArray(sorts, FieldSort.class);
            for (FieldSort fieldSort : sortObjs) {
                wrapper.orderBy(CharSequenceUtil.isNotBlank(fieldSort.f), !fieldSort.desc,
                        CharSequenceUtil.toUnderlineCase(fieldSort.f));
            }
        }
        return wrapper;
    }

    static class FiledFilter implements Serializable {
        private static final long serialVersionUID = 1L;
        /**
         * 字段名
         */
        private String f;
        /**
         * 逻辑运算符
         */
        private String o;
        /**
         * 值
         */
        private Object v;

        public String getF() {
            return f;
        }

        public void setF(String f) {
            this.f = f;
        }

        public String getO() {
            return o;
        }

        public void setO(String o) {
            this.o = o;
        }

        public Object getV() {
            return v;
        }

        public void setV(Object v) {
            this.v = v;
        }
    }

    static class FieldSort implements Serializable {
        private static final long serialVersionUID = 1L;
        /**
         * 字段名
         */
        private String f;
        /**
         * 是否降序，默认升序
         */
        private boolean desc;

        public String getF() {
            return f;
        }

        public void setF(String f) {
            this.f = f;
        }

        public boolean isDesc() {
            return desc;
        }

        public void setDesc(boolean desc) {
            this.desc = desc;
        }
    }

    public String getFilters() {
        return filters;
    }

    public void setFilters(String filters) {
        this.filters = filters;
    }

    public String getSorts() {
        return sorts;
    }

    public void setSorts(String sorts) {
        this.sorts = sorts;
    }
}
